package VLine

import (
	"fmt"
)

type Constructor struct {
	array  []*Token
	cursor int
}

func (constructor *Constructor) Get() *Token {
	return constructor.array[constructor.cursor]
}

func (constructor *Constructor) GetByCursor(cursor int) *Token {
	if cursor < len(constructor.array) {
		return constructor.array[cursor]
	}
	return constructor.array[len(constructor.array)-1]
}

func (constructor *Constructor) Pass() {
	constructor.cursor++
}

func (constructor *Constructor) Parser(array []*Token) *S_Block {
	constructor.array = array
	constructor.cursor = 0
	defer func() {
		err := recover()
		if err != nil {
			fmt.Printf("编译失败:%s \n%v", err, constructor.Get())
		}
	}()
	var block = constructor.G_Block()
	if constructor.Get().category != TOKEN_EOF {
		panic("解析失败")
	}
	return block
}

func (constructor *Constructor) G_Block() *S_Block {
	var statements = make([]interface{}, 0)
	for {
		var statement = constructor.G_Statement()
		for constructor.Get().category == TOKEN_SEMICOLON {
			constructor.Pass()
		}
		if statement == nil {
			break
		}
		statements = append(statements, statement)
	}
	return &S_Block{
		statements: statements,
	}
}

func (constructor *Constructor) G_Statement() interface{} {
	var s_assignment = constructor.G_Assignment()
	if s_assignment != nil {
		return s_assignment
	}
	var s_defineAssignment = constructor.G_DefineAssignment()
	if s_defineAssignment != nil {
		return s_defineAssignment
	}
	var s_functionCall = constructor.G_FunctionCall()
	if s_functionCall != nil {
		return s_functionCall
	}
	var s_if = constructor.G_If()
	if s_if != nil {
		return s_if
	}
	var s_for = constructor.G_For()
	if s_for != nil {
		return s_for
	}
	var s_import = constructor.G_Import()
	if s_import != nil {
		return s_import
	}
	var g_return = constructor.G_Return()
	if g_return != nil {
		return g_return
	}
	var g_break = constructor.G_Break()
	if g_break != nil {
		return g_break
	}
	var g_continue = constructor.G_Continue()
	if g_continue != nil {
		return g_continue
	}
	return nil
}

func (constructor *Constructor) G_Return() *S_Return {
	if constructor.Get().category == TOKEN_RETURN {
		constructor.Pass()
		var s_expression = constructor.G_Expression()
		if len(s_expression.list) == 0 {
			s_expression = nil
		}
		return &S_Return{
			s_expression: s_expression,
		}
	}
	return nil
}

type S_Break struct {
}

func (constructor *Constructor) G_Break() *S_Break {
	if constructor.Get().category != TOKEN_BREAK {
		return nil
	}
	constructor.Pass()
	return &S_Break{}
}

func (s_break *S_Break) Translate(translate *Translate) {
	var layer = translate.layer
	for layer != nil {
		if layer.description == FOR {
			break
		}
		layer = layer.parent
	}
	if layer == nil {
		panic("break语句只能放在循环体内部")
	}
	var instruction = translate.PushInstruction(VM_JUMP, []int{0})
	translate.layer.breaks = append(translate.layer.breaks, instruction)
}

type S_Continue struct {
}

func (s_continue *S_Continue) Translate(translate *Translate) {
	var instruction = translate.PushInstruction(VM_JUMP, []int{0})
	translate.layer.breaks = append(translate.layer.continues, instruction)
}

func (constructor *Constructor) G_Continue() *S_Continue {
	if constructor.Get().category != TOKEN_CONTINUE {
		return nil
	}
	constructor.Pass()
	return &S_Continue{}
}

func (constructor *Constructor) G_FunctionCall() *S_FunctionCall {
	var start = constructor.cursor
	var s_value = constructor.G_Value()
	if s_value != nil {
		var _, ok = s_value.list[len(s_value.list)-1].(*S_Call)
		if ok {
			return &S_FunctionCall{
				s_value: s_value,
			}
		}
	}
	constructor.cursor = start
	return nil
}

func (constructor *Constructor) G_For() *S_For {
	if constructor.Get().category != TOKEN_FOR {
		return nil
	}
	constructor.Pass()
	var s_for = &S_For{}

	var cursor = constructor.cursor
	if constructor.Get().category == TOKEN_ID {
		var token = constructor.Get()
		constructor.Pass()
		if constructor.Get().category == TOKEN_IN {
			constructor.Pass()
			var s_value = constructor.G_Value()
			if s_value != nil {
				if constructor.Get().category != TOKEN_LEFTBRACE {
					panic("没有找到 '{'")
				}
				constructor.Pass()
				var s_block = constructor.G_Block()
				if constructor.Get().category != TOKEN_RIGHTBRACE {
					panic("没有找到 '}'")
				}
				constructor.Pass()
				return &S_For{
					token:   token,
					s_value: s_value,
					s_block: s_block,
				}
			} else {
				return nil
			}
		} else {
			constructor.cursor = cursor
		}
	}

	var s_expression = constructor.G_Expression()
	if s_expression == nil {
		panic("在'elseif'语句中找不到判断表达式")
	}
	if constructor.Get().category != TOKEN_LEFTBRACE {
		panic("没有找到 '{'")
	}
	constructor.Pass()
	var s_block = constructor.G_Block()
	if constructor.Get().category != TOKEN_RIGHTBRACE {
		panic("没有找到 '}'")
	}
	constructor.Pass()
	s_for.s_expression = s_expression
	s_for.s_block = s_block
	return s_for
}

func (constructor *Constructor) G_If() *S_If {
	if constructor.Get().category != TOKEN_IF {
		return nil
	}
	constructor.Pass()
	var s_if = &S_If{}
	var s_expression = constructor.G_Expression()
	if s_expression == nil {
		panic("在'if'语句中找不到判断表达式")
	}
	if constructor.Get().category != TOKEN_LEFTBRACE {
		panic("没有找到 '{'")
	}
	constructor.Pass()
	var s_block = constructor.G_Block()
	if constructor.Get().category != TOKEN_RIGHTBRACE {
		panic("没有找到 '}'")
	}
	constructor.Pass()
	s_if.s_expression = s_expression
	s_if.s_block = s_block

	var s_elseif = make([]*S_ElseIf, 0)
	var value = constructor.G_ElseIf()
	for {
		if value == nil {
			break
		}
		s_elseif = append(s_elseif, value)
		value = constructor.G_ElseIf()
	}
	s_if.s_elseif = s_elseif
	s_if.s_else = constructor.G_Else()
	return s_if
}

func (constructor *Constructor) G_ElseIf() *S_ElseIf {
	if constructor.Get().category != TOKEN_ELSEIF {
		return nil
	}
	constructor.Pass()
	var s_elseif = &S_ElseIf{}
	var s_expression = constructor.G_Expression()
	if s_expression == nil {
		panic("missing expression in elseif statement")
	}
	if constructor.Get().category != TOKEN_LEFTBRACE {
		panic("没有找到 '{'")
	}
	constructor.Pass()
	var s_block = constructor.G_Block()
	if constructor.Get().category != TOKEN_RIGHTBRACE {
		panic("没有找到 '}'")
	}
	constructor.Pass()
	s_elseif.s_expression = s_expression
	s_elseif.s_block = s_block
	return s_elseif
}

func (constructor *Constructor) G_Else() *S_Else {
	if constructor.Get().category != TOKEN_ELSE {
		return nil
	}
	constructor.Pass()
	var s_else = &S_Else{}
	if constructor.Get().category == TOKEN_LEFTBRACE {
		constructor.Pass()
	}
	var s_block = constructor.G_Block()
	if constructor.Get().category == TOKEN_RIGHTBRACE {
		constructor.Pass()
	}
	s_else.s_block = s_block
	return s_else
}

func (constructor *Constructor) G_Assignment() *S_Assignment {
	var cursor = constructor.cursor
	var s_var = constructor.G_Var()
	if s_var == nil || constructor.Get().category != TOKEN_ASSIGN {
		constructor.cursor = cursor
		return nil
	}
	constructor.Pass()
	var s_expression = constructor.G_Expression()
	return &S_Assignment{
		s_var:        s_var,
		s_expression: s_expression,
	}
}

func (constructor *Constructor) G_Var() *S_Var {
	var s_value = constructor.G_Value()
	if s_value != nil {
		var key = s_value.list[len(s_value.list)-1]
		var _, ok = key.(*S_Call)
		if ok {
			return nil
		}
		_, ok = key.(*S_Table)
		if ok {
			return nil
		}
		_, ok = key.(*S_Function)
		if ok {
			return nil
		}
		s_value.list = s_value.list[:len(s_value.list)-1]
		return &S_Var{
			s_value: s_value,
			key:     key,
		}
	}
	return nil
}

func (constructor *Constructor) G_DefineAssignment() *S_DefineAssignment {
	if constructor.Get().category != TOKEN_LET &&
		constructor.Get().category != TOKEN_CONST &&
		constructor.Get().category != TOKEN_STATIC {
		return nil
	}
	var token = constructor.Get()
	constructor.Pass()
	var nameList = constructor.G_NameList()
	if len(nameList.tokens) == 0 {
		panic("没有设置变量名")
	}
	if constructor.Get().category == TOKEN_ASSIGN {
		constructor.Pass()
		var s_list = constructor.G_List()
		if s_list == nil {
			panic("没有找到右值")
		}
		return &S_DefineAssignment{
			token:      token,
			s_nameList: nameList,
			s_list:     s_list,
		}
	} else {
		return &S_DefineAssignment{
			s_nameList: nameList,
			s_list:     nil,
		}
	}
}

func (constructor *Constructor) G_NameList() *S_NameList {
	var list = make([]*Token, 0)
	var token = constructor.Get()
	for token.category == TOKEN_ID {
		constructor.Pass()
		list = append(list, token)
		if constructor.Get().category == TOKEN_COMMA {
			constructor.Pass()
			token = constructor.Get()
		} else {
			break
		}
	}
	return &S_NameList{
		tokens: list,
	}
}

func (constructor *Constructor) G_List() *S_List {
	var list = make([]*S_Expression, 0)
	for {
		var expression = constructor.G_Expression()
		if expression == nil {
			break
		}
		list = append(list, expression)
		if constructor.Get().category != TOKEN_COMMA {
			break
		}
		constructor.Pass()
	}
	if len(list) == 0 {
		return nil
	}
	return &S_List{
		s_expressions: list,
	}
}

func (constructor *Constructor) G_Expression() *S_Expression {
	var expression = &S_Expression{
		list: make([]interface{}, 0),
	}
	G_ExpressionAndOr(constructor, expression)
	if len(expression.list) == 0 {
		return nil
	}
	return expression
}

func G_ExpressionAndOr(constructor *Constructor, expression *S_Expression) {
	G_ExpressionEqualNotEqual(constructor, expression)
	var token = constructor.Get()
	if token.category == TOKEN_AND ||
		token.category == TOKEN_OR {
		constructor.Pass()
		G_ExpressionAndOr(constructor, expression)
		expression.list = append(expression.list, token)
	}
}

func G_ExpressionEqualNotEqual(constructor *Constructor, expression *S_Expression) {
	G_ExpressionCompare(constructor, expression)
	var token = constructor.Get()
	if token.category == TOKEN_EQUAL ||
		token.category == TOKEN_NOTEQUAL {
		constructor.Pass()
		G_ExpressionEqualNotEqual(constructor, expression)
		expression.list = append(expression.list, token)
	}
}

func G_ExpressionCompare(constructor *Constructor, expression *S_Expression) {
	G_ExpressionAddSubConcat(constructor, expression)
	var token = constructor.Get()
	if token.category == TOKEN_GREATER ||
		token.category == TOKEN_LESS ||
		token.category == TOKEN_GREATEREQUAL ||
		token.category == TOKEN_LESSEQUAL {
		constructor.Pass()
		G_ExpressionCompare(constructor, expression)
		expression.list = append(expression.list, token)
	}
}

func G_ExpressionAddSubConcat(constructor *Constructor, expression *S_Expression) {
	G_ExpressionMulDivModPower(constructor, expression)
	var token = constructor.Get()
	if token.category == TOKEN_ADD ||
		token.category == TOKEN_SUB ||
		token.category == TOKEN_CONCAT {
		constructor.Pass()
		G_ExpressionAddSubConcat(constructor, expression)
		expression.list = append(expression.list, token)
	}
}

func G_ExpressionMulDivModPower(constructor *Constructor, expression *S_Expression) {
	G_ExpressionModPower(constructor, expression)
	var token = constructor.Get()
	if token.category == TOKEN_MUL ||
		token.category == TOKEN_DIV ||
		token.category == TOKEN_MOD ||
		token.category == TOKEN_POWER {
		constructor.Pass()
		G_ExpressionMulDivModPower(constructor, expression)
		expression.list = append(expression.list, token)
	}
}

func G_ExpressionModPower(constructor *Constructor, expression *S_Expression) {
	G_ExpressionSign(constructor, expression)
	var token = constructor.Get()
	if token.category == TOKEN_MOD ||
		token.category == TOKEN_POWER {
		constructor.Pass()
		G_ExpressionModPower(constructor, expression)
		expression.list = append(expression.list, token)
	}
}

func G_ExpressionSign(constructor *Constructor, expression *S_Expression) {
	var token = constructor.Get()
	switch token.category {
	case TOKEN_ADD:
		constructor.Pass()
		G_ExpressionSign(constructor, expression)
		token.category = TOKEN_POS
		expression.list = append(expression.list, token)
	case TOKEN_SUB:
		constructor.Pass()
		G_ExpressionSign(constructor, expression)
		token.category = TOKEN_NEG
		expression.list = append(expression.list, token)
	case TOKEN_NOT:
		constructor.Pass()
		G_ExpressionSign(constructor, expression)
		expression.list = append(expression.list, token)
	}
	G_Atom(constructor, expression)
}

func G_Atom(constructor *Constructor, expression *S_Expression) {
	var token = constructor.Get()
	if token.category == TOKEN_NIL ||
		token.category == TOKEN_FALSE ||
		token.category == TOKEN_TRUE ||
		token.category == TOKEN_NUMBER ||
		token.category == TOKEN_STRING {
		constructor.Pass()
		expression.list = append(expression.list, token)
	} else {
		var value = constructor.G_Value()
		if value != nil {
			expression.list = append(expression.list, value)
		}
	}

}

func (constructor *Constructor) G_Get() *S_Get {
	if constructor.Get().category == TOKEN_LEFTBRACKET {
		constructor.Pass()
		var value = constructor.G_Expression()
		if constructor.Get().category == TOKEN_RIGHTBRACKET {
			constructor.Pass()
			return &S_Get{
				s_expression: value,
			}
		}
	}
	return nil
}

func (constructor *Constructor) G_Call() *S_Call {
	if constructor.Get().category != TOKEN_LEFTPARENTHESIS {
		return nil
	}
	constructor.Pass()
	var s_valueList = constructor.G_ValueList()
	if constructor.Get().category != TOKEN_RIGHTPARENTHESIS {
		return nil
	}
	constructor.Pass()
	if s_valueList != nil {
		return &S_Call{
			s_valueList: s_valueList,
		}
	}
	return nil
}

func (constructor *Constructor) G_Point() *S_Point {
	var token = constructor.Get()
	var token1 = constructor.GetByCursor(constructor.cursor + 1)
	if token.category == TOKEN_POINT && token1.category == TOKEN_ID {
		constructor.Pass()
		constructor.Pass()
		return &S_Point{
			token: token1,
		}
	}
	return nil
}

func (constructor *Constructor) G_Value() *S_Value {
	var cursor = constructor.cursor
	var list = make([]interface{}, 0)

	var s_table = constructor.G_Table()
	if s_table != nil {
		list = append(list, s_table)
	} else {
		var s_function = constructor.G_Function()
		if s_function != nil {
			list = append(list, s_function)
		} else {
			if constructor.Get().category == TOKEN_ID {
				list = append(list, constructor.Get())
				constructor.Pass()
			} else {
				if constructor.Get().category != TOKEN_LEFTPARENTHESIS {
					constructor.cursor = cursor
					return nil
				}
				constructor.Pass()
				var s_expression = constructor.G_Expression()
				if constructor.Get().category != TOKEN_RIGHTPARENTHESIS {
					constructor.cursor = cursor
					return nil
				}
				constructor.Pass()
				if s_expression != nil {
					list = append(list, s_expression)
				} else {
					constructor.cursor = cursor
					return nil
				}
			}
		}
	}
	for {
		var s_call = constructor.G_Call()
		if s_call != nil {
			list = append(list, s_call)
			continue
		}
		var s_get = constructor.G_Get()
		if s_get != nil {
			list = append(list, s_get)
			continue
		}
		var s_point = constructor.G_Point()
		if s_point != nil {
			list = append(list, s_point)
			continue
		}
		break
	}
	if len(list) == 0 {
		constructor.cursor = cursor
		return nil
	}
	return &S_Value{
		list: list,
	}
}

func (constructor *Constructor) G_Function() *S_Function {
	if constructor.Get().category != TOKEN_FUNCTION {
		return nil
	}
	constructor.Pass()
	var s_nameList *S_NameList
	if constructor.Get().category == TOKEN_LEFTPARENTHESIS {
		constructor.Pass()
		s_nameList = constructor.G_NameList()
		if len(s_nameList.tokens) == 0 {
			panic("没有形式参数")
		}
		if constructor.Get().category != TOKEN_RIGHTPARENTHESIS {
			panic("缺少')'")
		}
		constructor.Pass()
	}

	if constructor.Get().category != TOKEN_LEFTBRACE {
		panic("缺少'{'")
	}
	constructor.Pass()
	var s_block = constructor.G_Block()
	if constructor.Get().category != TOKEN_RIGHTBRACE {
		panic("缺少'}'")
	}
	constructor.Pass()
	if s_block != nil {
		return &S_Function{
			s_nameList: s_nameList,
			s_block:    s_block,
		}
	}
	return nil
}

func (constructor *Constructor) G_KeyAssignment() *S_KeyAssignment {
	var token = constructor.Get()
	if token.category == TOKEN_ID || token.category == TOKEN_STRING {
		if constructor.GetByCursor(constructor.cursor+1).category == TOKEN_ASSIGN {
			constructor.Pass()
			constructor.Pass()
			return &S_KeyAssignment{
				key:   token,
				value: constructor.G_Expression(),
			}
		}
	}
	return nil
}

func (constructor *Constructor) G_ValueList() *S_ValueList {
	var s_expressions = make([]*S_Expression, 0)
	var s_keyAssignments = make([]*S_KeyAssignment, 0)
	for {
		if constructor.Get().category == TOKEN_COMMA || constructor.Get().category == TOKEN_SEMICOLON {
			constructor.Pass()
		}
		var s_keyAssignment = constructor.G_KeyAssignment()
		if s_keyAssignment != nil {
			s_keyAssignments = append(s_keyAssignments, s_keyAssignment)
			continue
		}
		var s_expression = constructor.G_Expression()
		if s_expression != nil {
			s_expressions = append(s_expressions, s_expression)
			continue
		}
		break
	}
	return &S_ValueList{
		s_expressions:    s_expressions,
		s_keyAssignments: s_keyAssignments,
	}
}
func (constructor *Constructor) G_Table() *S_Table {
	if constructor.Get().category != TOKEN_LEFTBRACE {
		return nil
	}
	constructor.Pass()
	var s_valueList = constructor.G_ValueList()
	if constructor.Get().category != TOKEN_RIGHTBRACE {
		return nil
	}
	constructor.Pass()
	return &S_Table{
		s_valueList: s_valueList,
	}
}

func (constructor *Constructor) G_Import() *S_Import {
	if constructor.Get().category != TOKEN_IMPORT {
		return nil
	}
	constructor.Pass()
	var name = constructor.Get()
	var from *Token
	constructor.Pass()
	if constructor.Get().category == TOKEN_FROM {
		constructor.Pass()
		from = constructor.Get()
		constructor.Pass()
	}
	return &S_Import{
		name: name,
		from: from,
	}
}
